#include <assert.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "viawin.h"

#ifdef _DEBUG
#include <FreeImage.h>
#endif

using namespace nVIA;

// typedef struct VIADIALOG {
// 	HWND	hwnd;
// 	HANDLE	hViaCommands;
// 	CWin*	pWin;
// } VIADIALOG, *PVIADIALOG;

char* CGui::m_szAppName = _T("VIAssist");
WNDPROC	CGui::m_wndProc = CViaWin_WndProc;

//////////////////////////////////////////////////////////////////////////
/// CallBack funtions
//////////////////////////////////////////////////////////////////////////

LRESULT CALLBACK CViaWin_WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	TCHAR szExp[1024];
	static TCHAR szTitle[1024];
	CWin* pWin = (CWin*) GetWindowLong(hWnd, 0);
	static HWND hwndEdit[4], hwndStatic[4], hwndToolbar;
	HWND hWnd_c;
	RECT rt;

	long id = GetCurrentThreadId();
	
	switch (message) 
	{
	case WM_CHAR:
		{
			char c = (char) wParam;
			if (c == '\n' && pWin)
				pWin->UpdateData();
		}
		break;
	case WM_COMMAND:
		wmId    = LOWORD(wParam); 
		wmEvent = HIWORD(wParam); 
		hWnd_c = (HWND) lParam;
		if (pWin)
			pWin->OnToolbar(wmId, wmEvent, hWnd_c);
		break;
	case WM_CREATE:
		{
			 CREATESTRUCT* p = (CREATESTRUCT*) lParam;
			 CWin* pWin = (CWin*) p->lpCreateParams;
			 pWin->OnCreate(hWnd);
		}			
		break;
	case WM_SIZE:
		{
			int cxClient = LOWORD (lParam) ;
			int cyClient = HIWORD (lParam) ;
			RECT rt = {0, 0, cxClient, cyClient};
			if (pWin)
				pWin->OnSize(&rt);
		}
		break;
// 	case WM_MOUSEMOVE:
// 		{
// 			int x = LOWORD (lParam) ;
// 			int y = HIWORD (lParam) ;
// 			GetClientRect(hWnd, &rt);
// 			if (y - rt.top > 24)
// 				SetFocus(hWnd);
// 		}
// 		
// 		break;
	case WM_LBUTTONDOWN:
		{
			int x = LOWORD(lParam);
			int y = HIWORD(lParam);
			wmEvent = wParam;
			if (pWin)
				pWin->OnLButtonDown(wmEvent, x, y);
		}
		
		break;
	case WM_PAINT:
		if (pWin)
			pWin->OnPaint();
		break;
//	case WM_DESTROY:
		//return 0;
		//break;
	case WM_ERASEBKGND:
		return 1;
		break;
	default:
		break;
	}
   return DefWindowProc(hWnd, message, wParam, lParam);
}

DWORD WINAPI viaDialog_Thread(PVOID pParm)
{
	MSG         msg ;
	CWin* pWin = (CWin*) pParm;
// 	CData**		p = GetTlsDataEx();
// 
// 	if (p == NULL)
// 		goto exit;
// 
// 	*p = new CData(pVia->hViaCommands);
//	(*p)->SetWin(pVia->pWin);
	
	//CData *p = (CData *) ::GetWindowLong(pWin->GetWnd(), 0);
	//long e = GetLastError();
	
	::ShowWindow (pWin->GetWnd(), SW_SHOW) ;
	::UpdateWindow (pWin->GetWnd()) ;

	while (::GetMessage (&msg, NULL, 0, 0))
	{
		::TranslateMessage (&msg) ;
		::DispatchMessage (&msg) ;
	}

	::TerminateThread(pWin->m_thread, 0);
	pWin->m_threadID = 0;
	return 1;
}

//////////////////////////////////////////////////////////////////////////
/// CWin
//////////////////////////////////////////////////////////////////////////

CWin::CWin(CGui* pGui)
:m_pGui(pGui)
{
	m_threadID = -1;
	m_pData = NULL;
	m_nToolbarHeight = 0;
	Create();
}

int CWin::Create()
{
	m_hWnd = CreateWindow (m_pGui->GetAppName(), m_pGui->GetAppName(),
		/*WS_VISIBLE | */WS_OVERLAPPEDWINDOW, 
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,  
		NULL,  NULL,  
		m_pGui->GetInstance(), 
		(LPVOID)this) ;	// Before CreateWindow return, WndProce will be called with
						// WM_CREATE msg. So I must pass `this' by CREATESTRUCT.

	LONG l, e;
	//CData *p = new CData(m_hViaCommands);
	//p->SetWin(this);
	//e = ::GetLastError();
	//SetLastError(0);
	if (0 == ::SetWindowLong(m_hWnd, 0, (LONG)this) && (e = ::GetLastError()) != 0)
		return FALSE;
// 	::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW);
// 	::SetLastError(0);
// 	if (0 == (l = ::GetWindowLong(m_hWnd, 0)) && (e = ::GetLastError()) != 0)
// 		return FALSE;

	if (m_pData) {
		delete m_pData;
		m_pData = NULL;
	}
	m_pData = new CData(m_pGui->GetViaCommands());
	int i = sizeof(m_StatusEdit);
	memset(m_StatusEdit, 0, sizeof(m_StatusEdit));
	for (i = 0; i < 4; i++)
		m_szEdit[i][0] = 0;
	
	m_bDataDirty = FALSE;
	m_bSync = FALSE;

	return TRUE;
}

void CWin::Run()
{
// 	static VIADIALOG param;
// 	param.hwnd = m_hWnd;
// 	param.hViaCommands = m_hViaCommands;
// 	param.pWin = this;
	//m_threadID = ::_beginthread(viaDialog_Thread, 1, (PVOID)this);
	m_thread = ::CreateThread(NULL, 0, viaDialog_Thread, (PVOID)this, 0, &m_threadID);
	long e = GetLastError();
}

void CWin::Release()
{
	if (m_pData) {
		delete m_pData;
		m_pData = NULL;
	}
	DestroyWnd();
	if (m_threadID) {
		::TerminateThread(m_thread, 0);
		m_threadID = 0;
	}
	// todo
	// 1. How to know the thread has ended itself?
	// 2. How to know if the window is closed?
}

void	CWin::GetMetric()
{
	HDC dc = ::GetDC(m_hWnd);
	TEXTMETRIC tm;
	RECT rect;

	::GetTextMetrics(dc, &tm);
	::GetClientRect(m_hWnd, &rect);
	
	m_nToolbarHeight = 3 * tm.tmHeight / 2;
	m_nChildWndsWidth[ID_STATIC_DATA] = 
		m_nChildWndsWidth[ID_STATIC_WIDTH] = 
		m_nChildWndsWidth[ID_STATIC_HEIGHT] = 
		m_nChildWndsWidth[ID_STATIC_PITCH] = tm.tmAveCharWidth * 6;
	m_nChildWndsWidth[ID_EDIT_DATA] = tm.tmAveCharWidth * 24;
	m_nChildWndsWidth[ID_EDIT_WIDTH] = 
		m_nChildWndsWidth[ID_EDIT_HEIGHT] = 
		m_nChildWndsWidth[ID_EDIT_PITCH] = tm.tmAveCharWidth * 12;
// 	m_nChildWndsWidth[ID_STATIC_TOOLBOX] = m_nChildWndsWidth[ID_STATIC_DATA] * 4 +
// 		m_nChildWndsWidth[ID_EDIT_DATA] + m_nChildWndsWidth[ID_EDIT_WIDTH] * 3 +
// 		7;
	m_nChildWndsWidth[ID_STATIC_TOOLBOX] = rect.right - rect.left;

	::ReleaseDC(m_hWnd, dc);
}

BOOL	CWin::OnCreate(HWND hWnd)
{
	// At this time, m_hWnd has not be initialized, so HWND must be passed from
	// outside.
	m_hChildWnds[ID_STATIC_TOOLBOX] = CreateWindow("static", NULL, 
		WS_CHILD | WS_VISIBLE | SS_GRAYRECT | SS_CENTER | COLOR_BTNFACE, 
		0, 0, 0, 0, 
		hWnd, (HMENU) ID_STATIC_TOOLBOX, 
		m_pGui->GetInstance(), NULL);
	m_hChildWnds[ID_STATIC_DATA] = CreateWindow("static", _T("data"), 
		WS_CHILD | WS_VISIBLE | SS_CENTER, 
		0, 0, 0, 0, 
		hWnd, (HMENU) ID_STATIC_DATA, 
		m_pGui->GetInstance(), NULL);
	m_hChildWnds[ID_EDIT_DATA] = CreateWindow ("edit", NULL,
		WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL ,
		0, 0, 0, 0,
		hWnd, (HMENU) ID_EDIT_DATA,
		m_pGui->GetInstance(), NULL) ;
	m_hChildWnds[ID_STATIC_WIDTH] = CreateWindow("static", _T("width"), 
		WS_CHILD | WS_VISIBLE | SS_CENTER, 
		0, 0, 0, 0, 
		hWnd, (HMENU)ID_STATIC_WIDTH, 
		m_pGui->GetInstance(), NULL);
	m_hChildWnds[ID_EDIT_WIDTH] = CreateWindow ("edit", NULL,
		WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL ,
		0, 0, 0, 0,
		hWnd, (HMENU) ID_EDIT_WIDTH,
		m_pGui->GetInstance(), NULL) ;
	m_hChildWnds[ID_STATIC_HEIGHT] = CreateWindow("static", _T("height"), 
		WS_CHILD | WS_VISIBLE | SS_CENTER, 
		0, 0, 0, 0, 
		hWnd, (HMENU) ID_STATIC_HEIGHT,
		m_pGui->GetInstance(), NULL);
	m_hChildWnds[ID_EDIT_HEIGHT] = CreateWindow ("edit", NULL,
		WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL ,
		0, 0, 0, 0,
		hWnd, (HMENU)ID_EDIT_HEIGHT,
        m_pGui->GetInstance(), NULL) ;
	m_hChildWnds[ID_STATIC_PITCH] = CreateWindow("static", _T("pitch"), 
		WS_CHILD | WS_VISIBLE | SS_CENTER, 
		0, 0, 0, 0, 
		hWnd, (HMENU) ID_STATIC_PITCH,
		m_pGui->GetInstance(), NULL);
	m_hChildWnds[ID_EDIT_PITCH] = CreateWindow ("edit", NULL,
		WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL ,
		0, 0, 0, 0,
		hWnd, (HMENU)ID_EDIT_PITCH,
        m_pGui->GetInstance(), NULL) ;

	return TRUE;
}

void 	CWin::GetChildPos(RECT* prt)
{
	m_ptChildWndsPos[ID_STATIC_TOOLBOX].y = prt->top;
	m_ptChildWndsPos[ID_STATIC_WIDTH].y = prt->top;
	m_ptChildWndsPos[ID_STATIC_HEIGHT].y = prt->top;
	m_ptChildWndsPos[ID_STATIC_DATA].y = prt->top;
	m_ptChildWndsPos[ID_STATIC_PITCH].y = prt->top;
	m_ptChildWndsPos[ID_EDIT_DATA].y = prt->top;
	m_ptChildWndsPos[ID_EDIT_WIDTH].y = prt->top;
	m_ptChildWndsPos[ID_EDIT_HEIGHT].y = prt->top;
	m_ptChildWndsPos[ID_EDIT_PITCH].y = prt->top;

	m_ptChildWndsPos[ID_STATIC_TOOLBOX].x = prt->left;
	m_ptChildWndsPos[ID_STATIC_DATA].x = prt->left;
	m_ptChildWndsPos[ID_EDIT_DATA].x = m_ptChildWndsPos[ID_STATIC_DATA].x + m_nChildWndsWidth[ID_STATIC_DATA] + 1;
	m_ptChildWndsPos[ID_STATIC_WIDTH].x = m_ptChildWndsPos[ID_EDIT_DATA].x + m_nChildWndsWidth[ID_EDIT_DATA] + 1;
	m_ptChildWndsPos[ID_EDIT_WIDTH].x = m_ptChildWndsPos[ID_STATIC_WIDTH].x + m_nChildWndsWidth[ID_STATIC_WIDTH] + 1;
	m_ptChildWndsPos[ID_STATIC_HEIGHT].x = m_ptChildWndsPos[ID_EDIT_WIDTH].x + m_nChildWndsWidth[ID_EDIT_WIDTH] + 1;
	m_ptChildWndsPos[ID_EDIT_HEIGHT].x = m_ptChildWndsPos[ID_STATIC_HEIGHT].x + m_nChildWndsWidth[ID_STATIC_HEIGHT] + 1;
	m_ptChildWndsPos[ID_STATIC_PITCH].x = m_ptChildWndsPos[ID_EDIT_HEIGHT].x + m_nChildWndsWidth[ID_EDIT_HEIGHT] + 1;
	m_ptChildWndsPos[ID_EDIT_PITCH].x = m_ptChildWndsPos[ID_STATIC_PITCH].x + m_nChildWndsWidth[ID_STATIC_PITCH] + 1;
}

BOOL	CWin::OnSize(RECT* prt)
{
	GetMetric();
	GetChildPos(prt);

	MoveWindow(m_hChildWnds[ID_STATIC_TOOLBOX], m_ptChildWndsPos[ID_STATIC_TOOLBOX].x, m_ptChildWndsPos[ID_STATIC_TOOLBOX].y,
		m_nChildWndsWidth[ID_STATIC_TOOLBOX], m_nToolbarHeight, TRUE);
	MoveWindow(m_hChildWnds[ID_STATIC_WIDTH], m_ptChildWndsPos[ID_STATIC_WIDTH].x, m_ptChildWndsPos[ID_STATIC_WIDTH].y,
		m_nChildWndsWidth[ID_STATIC_WIDTH], m_nToolbarHeight, TRUE);
	MoveWindow(m_hChildWnds[ID_STATIC_HEIGHT], m_ptChildWndsPos[ID_STATIC_HEIGHT].x, m_ptChildWndsPos[ID_STATIC_HEIGHT].y,
		m_nChildWndsWidth[ID_STATIC_HEIGHT], m_nToolbarHeight, TRUE);
	MoveWindow(m_hChildWnds[ID_STATIC_DATA], m_ptChildWndsPos[ID_STATIC_DATA].x, m_ptChildWndsPos[ID_STATIC_DATA].y,
		m_nChildWndsWidth[ID_STATIC_DATA], m_nToolbarHeight, TRUE);
	MoveWindow(m_hChildWnds[ID_STATIC_PITCH], m_ptChildWndsPos[ID_STATIC_PITCH].x, m_ptChildWndsPos[ID_STATIC_PITCH].y,
		m_nChildWndsWidth[ID_STATIC_PITCH], m_nToolbarHeight, TRUE);
	MoveWindow(m_hChildWnds[ID_EDIT_DATA], m_ptChildWndsPos[ID_EDIT_DATA].x, m_ptChildWndsPos[ID_EDIT_DATA].y,
		m_nChildWndsWidth[ID_EDIT_DATA], m_nToolbarHeight, TRUE);
	MoveWindow(m_hChildWnds[ID_EDIT_WIDTH], m_ptChildWndsPos[ID_EDIT_WIDTH].x, m_ptChildWndsPos[ID_EDIT_WIDTH].y,
		m_nChildWndsWidth[ID_EDIT_WIDTH], m_nToolbarHeight, TRUE);
	MoveWindow(m_hChildWnds[ID_EDIT_HEIGHT], m_ptChildWndsPos[ID_EDIT_HEIGHT].x, m_ptChildWndsPos[ID_EDIT_HEIGHT].y,
		m_nChildWndsWidth[ID_EDIT_HEIGHT], m_nToolbarHeight, TRUE);
	MoveWindow(m_hChildWnds[ID_EDIT_PITCH], m_ptChildWndsPos[ID_EDIT_PITCH].x, m_ptChildWndsPos[ID_EDIT_PITCH].y,
		m_nChildWndsWidth[ID_EDIT_PITCH], m_nToolbarHeight, TRUE);
	
	return TRUE;
}

BOOL	CWin::OnToolbar(int nWndId, int nNotify, HWND hWnd)
{
	if (m_hChildWnds[nWndId] != hWnd)
		return FALSE;

	// edit control
	if (nWndId >= 0 && nWndId < 4) {
		switch (nNotify) {
		case EN_KILLFOCUS:
			if (m_StatusEdit[nWndId] != 0) {
				WORD* p = (WORD*) m_szEdit[nWndId];
				*p = EDIT_LINE_NUM;
				SendMessage(hWnd, EM_GETLINE, (WPARAM)0, (LPARAM)p);
				m_StatusEdit[nWndId] = 0;
			}
			break;
		case EN_CHANGE:
			m_StatusEdit[nWndId] = 1;
			break;
		case EN_UPDATE:
			m_bDataDirty = TRUE;
// 			static n = 0;
// 			n++;
// 			_stprintf(szTitle, _T("%s - %s:%d"), pWin->GetAppName(), _T("data updated"), n);
// 			SetWindowText(hWnd, szTitle);
			break;
		}
	}

// 	switch (wmId)
// 	{
// 	case ID_EDIT_DATA:
// 		//_stprintf(szTitle, _T("%s - %s"), pWin->GetAppName(), _T("edit data"));
// 		//SetWindowText(hWnd, szTitle);
// 		switch (wmEvent) {
// 			
// 		case EN_KILLFOCUS:
// 			SetFocus(hWnd);
// 			break;
// 		case EN_UPDATE:
// 			static n = 0;
// 			n++;
// 			_stprintf(szTitle, _T("%s - %s:%d"), pWin->GetAppName(), _T("data updated"), n);
// 			SetWindowText(hWnd, szTitle);
// 			break;
// 		}
// 		break;
// 		case ID_EDIT_WIDTH:
// 			switch (wmEvent) {
// 			case EN_KILLFOCUS:
// 				SetFocus(hWnd);
// 				break;
// 			case EN_UPDATE:
// 				_stprintf(szTitle, _T("%s - %s"), pWin->GetAppName(), _T("width updated"));
// 				SetWindowText(hWnd, szTitle);
// 				break;
// 			}
// 			break;
// 			case ID_EDIT_HEIGHT:
// 				switch (wmEvent) {
// 				case EN_KILLFOCUS:
// 					SetFocus(hWnd);
// 					break;
// 				case EN_UPDATE:
// 					_stprintf(szTitle, _T("%s - %s"), pWin->GetAppName(), _T("height updated"));
// 					SetWindowText(hWnd, szTitle);
// 					break;
// 				}
// 				break;
// 				default:
// 					break;
// 	}

	return TRUE;
}

BOOL	CWin::OnLButtonDown(int nNotify, int x, int y)
{
	switch (nNotify) {
	case MK_LBUTTON:
		if (y > m_nToolbarHeight) {
			SetFocus(m_hWnd);
			if (!UpdateData())
				return FALSE;
		}
		break;
	}
	return TRUE;
}

BOOL	CWin::UpdateData()
{
	int i;
#ifdef UNICODE
	static char buf[EDIT_LINE_NUM * 2];
#endif

	if (!m_bDataDirty)
		return TRUE;	// do nothing, return true

	for (i = 0; i < 4; i++) {
		if (_tcslen(m_szEdit[i]) <= 0)
			return TRUE;	// do nothing, return true
	}

#ifdef UNICODE
	if (0 == wcstombs(buf, m_szEdit[ID_EDIT_WIDTH], EDIT_LINE_NUM)) {
		if (!m_pData->SetWidth(buf))
			return FALSE;
	}
	else
		return FALSE;
	if (0 == wcstombs(buf, m_szEdit[ID_EDIT_HEIGHT], EDIT_LINE_NUM)) {
		if (!m_pData->SetHeight(buf))
			return FALSE;
	}
	else
		return FALSE;
	if (0 == wcstombs(buf, m_szEdit[ID_EDIT_PITCH], EDIT_LINE_NUM)) {
		if (!m_pData->SetPitch(buf))
			return FALSE;
	}
	else
		return FALSE;
	if (0 == wcstombs(buf, m_szEdit[ID_EDIT_DATA], EDIT_LINE_NUM)) {
		if (!m_pData->SetBits(buf))
			return FALSE;
	}
	else
		return FALSE;
#else
	if (!m_pData->SetWidth(m_szEdit[ID_EDIT_WIDTH]))
		return FALSE;
	if (!m_pData->SetHeight(m_szEdit[ID_EDIT_HEIGHT]))
		return FALSE;
	if (!m_pData->SetPitch(m_szEdit[ID_EDIT_PITCH]))
		return FALSE;
	if (!m_pData->SetBits(m_szEdit[ID_EDIT_DATA]))
		return FALSE;
#endif

	if (m_pData->UpdateData()) {
		RECT rect;
		m_bDataDirty = FALSE;
		m_bSync = TRUE;
#ifdef _DEBUG
		int width = m_pData->GetWidth();
		int height = m_pData->GetHeight();
		int pitch_s = m_pData->GetPitch();
		PBYTE bits_s = m_pData->GetBits();
		FIBITMAP* dib = FreeImage_Allocate(m_pData->GetWidth(), m_pData->GetHeight(), 24);
		PBYTE bits = FreeImage_GetBits(dib);
		int pitch = FreeImage_GetPitch(dib);
		int y;
		for (y = 0; y < height; y++) {
			memcpy(bits, bits_s, 3 * width);
			bits += pitch;
			bits_s += pitch_s;
		}
		FreeImage_Save(FIF_BMP, dib, "e:/tmp/via.bmp");
		FreeImage_Unload(dib);
#endif
		::GetClientRect (m_hWnd, &rect) ;
		rect.top += m_nToolbarHeight;
		::InvalidateRect(m_hWnd, &rect, TRUE);

		return TRUE;
	}
	
	return FALSE;
}

BOOL	CWin::OnPaint()
{
	HDC         hdc, hdcMem, workdc;
	PAINTSTRUCT ps ;
	RECT        rect;
	BITMAP bitmap  ;
	static HBITMAP hBitmap;
	BYTE	*bits ;
	HBRUSH bsh;
	int cxClient, cyClient;

	if (!m_bDataDirty && m_bSync) {
		hdc = ::BeginPaint (m_hWnd, &ps) ;
		::GetClientRect (m_hWnd, &rect) ;
		rect.top += m_nToolbarHeight;
		cxClient = rect.right - rect.left;
		cyClient = rect.bottom - rect.top;
#if 0
		hdcMem = ::CreateCompatibleDC (NULL);
		bsh = (HBRUSH) ::GetStockObject(BLACK_BRUSH);
		::FillRect(hdcMem, &rect, bsh);
		//hBitmap = ::CreateCompatibleBitmap(hdc, m_pData->GetWidth(), m_pData->GetHeight());
		//::SetBitmapBits (hBitmap, m_pData->GetPitch() * m_pData->GetHeight(), m_pData->GetBits()) ;
		hBitmap = ::CreateBitmap(m_pData->GetWidth(), m_pData->GetHeight(), 3, 8, m_pData->GetBits());
		long e = GetLastError();
		//::SelectObject(hdcMem, hBitmap);
		HBITMAP hbmT = (HBITMAP) ::SelectObject(hdcMem, hBitmap);
		BITMAP bm;
		GetObject(hBitmap, sizeof(bm), &bm);
		//::BitBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY);
		::StretchBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
		e = GetLastError();

		::SelectObject(hdcMem, hbmT);
		::DeleteDC(hdcMem);
#endif
		::SetStretchBltMode (hdc, COLORONCOLOR) ;
		::StretchDIBits(hdc, rect.left, rect.top, cxClient, cyClient, 0, 0, 
			m_pData->GetWidth(), m_pData->GetHeight(), m_pData->GetBits(), 
			m_pData->GetInfo(), DIB_RGB_COLORS, SRCCOPY);
		::EndPaint (m_hWnd, &ps) ;
		//::DeleteObject(hBitmap);

		return TRUE;
	}
	else {
		hdc = ::BeginPaint(m_hWnd, &ps);
		// TODO: Add any drawing code here...
		
		::GetClientRect (m_hWnd, &rect) ;
		rect.top -= m_nToolbarHeight;
		bsh = (HBRUSH) ::GetStockObject(BLACK_BRUSH);
		::FillRect(hdc, &rect, bsh);
		
		//viaEvaluateStr(g_hViaCommands, NULL, szExp, 1024);
		DrawText(hdc, _T("hello, vcimassist"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		EndPaint(m_hWnd, &ps);
	}

	return FALSE;
}

BOOL	CWin::OnDestroy()
{
	//PostMessage(m_hWnd, WM_QUIT, 0, 0);
	//SendMessage(m_hWnd, WM_QUIT, 0, 0);
	m_hWnd = NULL;
	return TRUE;
}

void	CWin::DestroyWnd()
{
	if (m_hWnd) {
		//::DestroyWindow(m_hWnd);
		m_hWnd = NULL;
	}
}

//////////////////////////////////////////////////////////////////////////
/// CGui
//////////////////////////////////////////////////////////////////////////

CGui::CGui(HINSTANCE hInstance, HANDLE hViaCommands)
{
	Create(hInstance, hViaCommands);
}

CGui::~CGui()
{
	Release();
}

int CGui::Create(HINSTANCE hInstance, HANDLE hViaCommands)
{
	if (hInstance == NULL)
		m_hInstance = GetModuleHandle(NULL);
	else
		m_hInstance = hInstance;
	// if set to NULL, there may be name conflictation.
//	m_hInstance = NULL;
	RegisterClass();
	m_nWin = 0;

	m_hViaCommands = (HANDLE) hViaCommands;

	return TRUE;
}

void CGui::Release()
{
	int i = 0;
	for (; i < m_nWin; i++) {
		delete m_lstWin[i];
	}
	m_nWin = 0;
}

int CGui::Dialog()
{
	if (m_nWin < VIA_DIALOG_MAX_NUM) {
		m_lstWin[m_nWin++] = new CWin(this);
		m_lstWin[m_nWin - 1]->Run();
		return TRUE;
	}
	return FALSE;
}

ATOM CGui::RegisterClass()
{	
	m_wndclass.cbSize        = sizeof (m_wndclass) ;
	m_wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS | CS_OWNDC;
	m_wndclass.lpfnWndProc   = m_wndProc ;
	m_wndclass.cbClsExtra    = 0 ;
	m_wndclass.cbWndExtra    = sizeof(LONG);
	m_wndclass.hInstance     = m_hInstance;
	m_wndclass.hIcon         = ::LoadIcon (NULL, IDI_APPLICATION) ;
	m_wndclass.hCursor       = ::LoadCursor (NULL, IDC_ARROW) ;
	m_wndclass.hbrBackground = (HBRUSH) ::GetStockObject (BLACK_BRUSH) ;
	m_wndclass.lpszMenuName  = NULL ;
	m_wndclass.lpszClassName = m_szAppName ;
	m_wndclass.hIconSm       = ::LoadIcon (NULL, IDI_APPLICATION) ;
	
	return m_WndClass = ::RegisterClassEx (&m_wndclass) ;
}

//////////////////////////////////////////////////////////////////////////
/// TLS functions
//////////////////////////////////////////////////////////////////////////
//extern DWORD g_dwViaTlsIndex;

/// Should be called inside thread function
//CData**	nVIA::GetTlsDataEx()
//{
// 	LPVOID lpvData; 
// 	
// 	lpvData = TlsGetValue(g_dwViaTlsIndex); 
// 	if (lpvData == NULL) {
// 		if (GetLastError() != ERROR_SUCCESS)
// 			return NULL;
// 		else {
// 			lpvData = (LPVOID) LocalAlloc(LPTR, sizeof(PVOID)); 
// 			if (lpvData == NULL) 
// 				return NULL;
// 			if (!TlsSetValue(g_dwViaTlsIndex, lpvData))
// 				return NULL;
// 		}
// 	} 
// 
// 	return (CData**) lpvData;
//	return 0;
//}

//CData**	nVIA::GetTlsData()
//{
//	return (CData**) TlsGetValue(g_dwViaTlsIndex); 
//	return 0;
//}

//////////////////////////////////////////////////////////////////////////
/// CData
//////////////////////////////////////////////////////////////////////////
BOOL	CData::getValue(char* expression, long* value)
{
	viaCommandsEvaluate(m_hViaCommands, expression, value, VIA_LONG);
	return TRUE;
}

BOOL	CData::getPointer(char* expression, PBYTE* pt)
{
	viaCommandsEvaluate(m_hViaCommands, expression, pt, VIA_PVOID);
	return TRUE;
}

BOOL	CData::UpdateData()
{
	if (!m_pBitmap) {
		m_pBitmap = new CBitmap(m_width, m_height, m_pitch, m_format);
	}
	else {
		m_pBitmap->Init(m_width, m_height, m_pitch, m_format);
	}

	if (viaCommandsReadMemory(m_hViaCommands, m_pBitmap->Bits(), m_bits, m_height * m_pitch)) {
		m_bHasImage = TRUE;
		return TRUE;
	}
	else {
		return m_bHasImage = FALSE;
	}
}
